#include "matrix.h"
#include <stdio.h>
#include <stdarg.h>

/**
 * These macros are here to help you create tests more easily and keep them
 * clear.
 *
 * The basic idea with unit-testing is create a test function for every real
 * function and inside the test function declare some variables and execute the
 * function under test.
 *
 * Use the ASSERT_MACRO to verify correctness of values.
 */

/**
 * Evaluates b and continues if b is true.
 * If b is false, ends the test by returning false and prints a detailed
 * message about the failure.
 */
#define ASSERT_TRUE(b)                                                         \
do                                                                             \
{                                                                              \
	if( !(b) )                                                                 \
	{                                                                          \
		printf("\nAssertion failed at %s:%d %s\n",__FILE__,__LINE__,#b);  	   \
		return false;                                                          \
	}                                                                          \
} while (0)

/**
 * Macro used for running a test from the main function
 */
#define RUN_TEST(test)                                                         \
do                                                                             \
{                                                                              \
	printf("Running "#test"... ");                                             \
	if( test )                                                                 \
	{                                                                          \
		printf( "[OK]\n" );                                                    \
	}                                                                          \
} while(0)

Matrix initMatrix( int rows, int columns, ... )
{
	Matrix result = matrixCreate( rows, columns );
	if( result == NULL )
	{
		return NULL;
	}

	va_list vl;
	va_start( vl, columns );

	for( int r = 0; r < rows; ++r )
	{
		for( int c = 0; c < columns; ++c )
		{
			double real = va_arg(vl,double);
			double imaginary = va_arg(vl,double);
			matrixSet( result, r, c, complexCreate( real, imaginary ) );
		}
	}

	va_end( vl );

	return result;
}

#define ASSERT_VALID(c) ASSERT_TRUE( complexIsValid( (c) ) )
#define ASSERT_INVALID(c) ASSERT_TRUE( !complexIsValid( (c) ) )
#define ASSERT_NULL(b) ASSERT_TRUE( (b) == MATRIX_NULL_ARGUMENT )
#define ASSERT_SUCCESS(b) ASSERT_TRUE( (b) == MATRIX_SUCCESS )
#define ASSERT_MATRIX_EQUAL(A,B) ASSERT_TRUE( matrixIsEqual( (A), (B) ) )
#define ASSERT_MATRIX_NOT_EQUAL(A,B) ASSERT_TRUE( !matrixIsEqual( (A), (B) ) )

bool testGetSetBoundary()
{
	Complex c = complexCreate( 0, 0 );
	ASSERT_INVALID( matrixGet( NULL, 2, 3 ) );
	ASSERT_NULL( matrixSet( NULL, 7, -4, c ) );

	Matrix m = matrixCreate( 17, 29 );
	ASSERT_INVALID( matrixGet( m, 0, -20 ) );
	ASSERT_INVALID( matrixGet( m, 0, 29 ) );
	ASSERT_INVALID( matrixGet( m, 0, 129 ) );
	ASSERT_INVALID( matrixGet( m, -20, 0 ) );
	ASSERT_INVALID( matrixGet( m, 17, 0 ) );
	ASSERT_INVALID( matrixGet( m, 123, 0 ) );
	ASSERT_INVALID( matrixGet( m, -20, -20 ) );
	ASSERT_INVALID( matrixGet( m, 17, 29 ) );
	ASSERT_INVALID( matrixGet( m, 123, 129 ) );
	ASSERT_TRUE( matrixSet( m, 0, -20, c ) == MATRIX_OUT_OF_BOUNDS );
	ASSERT_TRUE( matrixSet( m, 0, 29, c ) == MATRIX_OUT_OF_BOUNDS );
	ASSERT_TRUE( matrixSet( m, 0, 129, c ) == MATRIX_OUT_OF_BOUNDS );
	ASSERT_TRUE( matrixSet( m, -20, 0, c ) == MATRIX_OUT_OF_BOUNDS );
	ASSERT_TRUE( matrixSet( m, 17, 0, c ) == MATRIX_OUT_OF_BOUNDS );
	ASSERT_TRUE( matrixSet( m, 123, 0, c ) == MATRIX_OUT_OF_BOUNDS );
	ASSERT_TRUE( matrixSet( m, -20, -20, c ) == MATRIX_OUT_OF_BOUNDS );
	ASSERT_TRUE( matrixSet( m, 17, 29, c ) == MATRIX_OUT_OF_BOUNDS );
	ASSERT_TRUE( matrixSet( m, 123, 129, c ) == MATRIX_OUT_OF_BOUNDS );

	matrixDestroy( m );

	return true;
}

bool testGetSetFunctionality()
{
	int rows = 17;
	int columns = 29;
	Matrix m = matrixCreate( rows, columns );

	int sign = 1;
	for( int row = 0; row <rows; ++row )
	{
		for( int column = 0; column < columns; ++column )
		{
			Complex c = complexCreate( row * sign, column * -1 * sign );
			ASSERT_SUCCESS( matrixSet( m, row, column, c ) );
			ASSERT_TRUE( complexIsEqual( matrixGet(m,row,column), c ) );
			sign *= -1;
		}
	}

	matrixDestroy( m );

	return true;
}

bool testIsEqualBoundary()
{
	Matrix m1 = matrixCreate( 6, 2 );

	ASSERT_MATRIX_EQUAL( NULL,NULL );
	ASSERT_MATRIX_NOT_EQUAL( m1,NULL );
	ASSERT_MATRIX_NOT_EQUAL( NULL,m1 );

	matrixDestroy( m1 );

	return true;
}

bool testIsEqualFunctionality()
{
	Matrix m1 = matrixCreate( 6, 2 );
	Matrix m2 = initMatrix( 3, 3,
			 13.5086,  39.2154,   8.3012,   8.2644,  16.4205,   4.3866,
			  5.8499,  12.6278,  -7.8783,  33.0417, -19.6003, -31.1269,
			  9.2588,  46.8545,   1.3925,  -3.0251,   0.0176,  13.0428);
	Matrix m3 = initMatrix( 3, 3,
			 13.5086,  39.2154,   8.3012,   8.2644,  16.4205,   4.3866,
			  5.8499,  12.6278,  -7.8783,  33.0417, -19.6003, -31.1269,
			  9.2588,  46.8545,   1.3925,  -3.0251,   0.0176,  13.0428);
	Matrix m4 = initMatrix( 3, 3,
			 13.5086,  39.2154,   8.3012,   8.2644,  16.4205,   4.3866,
			 -5.8499,  12.6278,  -7.8783,  33.0417, -19.6003, -31.1269,
			  9.2588,  46.8545,   1.3925,  -3.0251,   0.0176,  13.0428);
	Matrix m5 = initMatrix( 4, 3,
			 13.5086,  39.2154,   8.3012,   8.2644,  16.4205,   4.3866,
			 -5.8499,  12.6278,  -7.8783,  33.0417, -19.6003, -31.1269,
			  9.2588,  46.8545,   1.3925,  -3.0251,   0.0176,  13.0428,
			  1.0,	   1.0,		  1.0,		1.0,	  1.0,	   1.0    );
	Matrix m6 = initMatrix( 3, 4,
			 13.5086,  39.2154,   8.3012,   8.2644,  16.4205,   4.3866, 1.0, 1.0,
			 -5.8499,  12.6278,  -7.8783,  33.0417, -19.6003, -31.1269, 1.0, 1.0,
			  9.2588,  46.8545,   1.3925,  -3.0251,   0.0176,  13.0428, 1.0, 1.0 );


	ASSERT_MATRIX_EQUAL( m1,m1 );
	ASSERT_MATRIX_NOT_EQUAL( m1,m2 );
	ASSERT_MATRIX_EQUAL( m2,m3 );
	ASSERT_MATRIX_EQUAL( m3,m2 );
	ASSERT_MATRIX_NOT_EQUAL( m3,m4 );
	ASSERT_MATRIX_NOT_EQUAL( m4,m3 );
	ASSERT_MATRIX_NOT_EQUAL( m4,m5 );
	ASSERT_MATRIX_NOT_EQUAL( m4,m6 );

	matrixDestroy( m1 );
	matrixDestroy( m2 );
	matrixDestroy( m3 );
	matrixDestroy( m4 );
	matrixDestroy( m5 );
	matrixDestroy( m6 );
	return true;
}

bool testCreateBoundary()
{
	ASSERT_TRUE( matrixCreate(0,0) == NULL );
	ASSERT_TRUE( matrixCreate(-1,0) == NULL );
	ASSERT_TRUE( matrixCreate(-1,-10) == NULL );
	ASSERT_TRUE( matrixCreate(4,-10) == NULL );

	return true;
}

bool testCreateFunctionality()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	int rows = 7;
	int columns = 8;
	Complex zero = complexCreate( 0, 0 );
	Matrix m = matrixCreate( rows, columns );
	for( int r = 0; r < rows; ++r )
	{
		for( int c = 0; c < columns; ++c )
		{
			ASSERT_TRUE( complexIsEqual( matrixGet(m,r,c), zero ) );
		}
	}

	matrixDestroy( m );
	/* NOT FOR STUDENTS END */
	return true;
}

bool testDestroy()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	matrixDestroy(NULL);
	/* NOT FOR STUDENTS END */
	return true;
}

bool testCreateUnit()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	Complex zero = complexCreate( 0, 0 );
	Complex one = complexCreate( 1, 0 );
	int n = 7;
	Matrix I = matrixCreateUnit( 7 );
	for( int r = 0; r < n; ++r )
	{
		for( int c = 0; c < n; ++c )
		{
			ASSERT_TRUE( complexIsEqual( matrixGet(I,r,c), r == c ? one : zero ) );
		}
	}

	matrixDestroy( I );
	/* NOT FOR STUDENTS END */
	return true;
}

bool testAddBoundary()
{
	Matrix m1 = matrixCreate( 6, 5 );
	Matrix m3 = matrixCreate( 13, 11 );
	Matrix m4 = matrixCreate( 12, 10 );
	Matrix m5 = matrixCreate( 12, 11 );
	Matrix m6 = matrixCreate( 13, 10 );

	ASSERT_NULL( matrixAdd(NULL, NULL) );
	ASSERT_NULL( matrixAdd(NULL, m1) );
	ASSERT_NULL( matrixAdd(m1, NULL) );

	ASSERT_TRUE( matrixAdd(m1, m3) == MATRIX_BAD_DIMENSIONS );
	ASSERT_TRUE( matrixAdd(m1, m4) == MATRIX_BAD_DIMENSIONS );
	ASSERT_TRUE( matrixAdd(m4, m5) == MATRIX_BAD_DIMENSIONS );
	ASSERT_TRUE( matrixAdd(m4, m6) == MATRIX_BAD_DIMENSIONS );

	matrixDestroy( m1 );
	matrixDestroy( m3 );
	matrixDestroy( m4 );
	matrixDestroy( m5 );
	matrixDestroy( m6 );

	return true;
}

bool testAddFunctionality()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	Matrix m1 = initMatrix( 6, 5,
			-36.8584,   6.1936, -37.6856,   4.2478, -15.1382,   1.5156, -10.2597,   7.4388,  -1.3487,   9.7963,
			-29.8706,   3.4318, -42.8484,   9.6614, -27.2463,  13.8947, -41.8660,  -2.4969,  37.0781,   6.9331,
			-37.6850,  -4.5447,   5.3857,  -2.9498,   0.9543,   1.4299,   0.1206,  -0.2220, -34.0706,  13.1711,
			 -0.9622,  12.6448,  25.6145,   7.2448,  38.1982,  -4.9177,  -6.4182,   5.6476, -10.3395, -13.5742,
			-28.8349, -10.8816, -17.6776,   9.7214,  12.1189,   3.4647,  46.7707,  13.7093,  40.1715,  -4.1508,
			 37.2138,   6.6870, -30.1756,  -5.1486, -37.4558,  -4.0415,  29.2906,  -4.9951,  39.2444,   4.7170 );

	// Duplicate m1 instead of using matrixCopy - we'd like Addition tests to
	// pass even if matrixCopy is faulty.
	Matrix m1Copy = initMatrix( 6, 5,
			-36.8584,   6.1936, -37.6856,   4.2478, -15.1382,   1.5156, -10.2597,   7.4388,  -1.3487,   9.7963,
			-29.8706,   3.4318, -42.8484,   9.6614, -27.2463,  13.8947, -41.8660,  -2.4969,  37.0781,   6.9331,
			-37.6850,  -4.5447,   5.3857,  -2.9498,   0.9543,   1.4299,   0.1206,  -0.2220, -34.0706,  13.1711,
			 -0.9622,  12.6448,  25.6145,   7.2448,  38.1982,  -4.9177,  -6.4182,   5.6476, -10.3395, -13.5742,
			-28.8349, -10.8816, -17.6776,   9.7214,  12.1189,   3.4647,  46.7707,  13.7093,  40.1715,  -4.1508,
			 37.2138,   6.6870, -30.1756,  -5.1486, -37.4558,  -4.0415,  29.2906,  -4.9951,  39.2444,   4.7170 );
	Matrix m2 = initMatrix( 6, 5,
			 16.1880,  23.5643, -15.6259,  21.7428,  -2.1444,   7.1688, -14.0346,  -6.2458,  12.3014,   7.5387,
			 27.5793, -10.4556,   3.1874,   2.4087,   4.4321,   1.0389, -26.3731,   4.5660, -26.7542, -20.9695,
			  6.0176,  14.7402,  35.3887,  11.1910, -16.8563,  -6.2567,  -1.7832,  18.2551, -34.9264,  -4.5704,
			-31.3400,  19.4095,  15.7445,   3.7612,  18.1783,  21.4196, -10.0405,  21.2416,   4.3684,   8.1796,
			 30.8604,   4.7788,  24.7448, -23.2330,   0.2838,  16.1471,  21.0323,   8.2547, -14.5402,  21.2526,
			 21.9272,  18.8168,  -4.8720,  -2.6200,  10.7171,  17.1052,  20.4616, -14.3680,  32.0769,  15.2366 );
	Matrix m2Copy = initMatrix( 6, 5,
			 16.1880,  23.5643, -15.6259,  21.7428,  -2.1444,   7.1688, -14.0346,  -6.2458,  12.3014,   7.5387,
			 27.5793, -10.4556,   3.1874,   2.4087,   4.4321,   1.0389, -26.3731,   4.5660, -26.7542, -20.9695,
			  6.0176,  14.7402,  35.3887,  11.1910, -16.8563,  -6.2567,  -1.7832,  18.2551, -34.9264,  -4.5704,
			-31.3400,  19.4095,  15.7445,   3.7612,  18.1783,  21.4196, -10.0405,  21.2416,   4.3684,   8.1796,
			 30.8604,   4.7788,  24.7448, -23.2330,   0.2838,  16.1471,  21.0323,   8.2547, -14.5402,  21.2526,
			 21.9272,  18.8168,  -4.8720,  -2.6200,  10.7171,  17.1052,  20.4616, -14.3680,  32.0769,  15.2366 );
	Matrix m1AddM2 = initMatrix(6, 5,
			-20.6704,  29.7579, -53.3115,  25.9906, -17.2826,   8.6844, -24.2943,   1.1930,  10.9527,  17.3350,
			 -2.2913,  -7.0238, -39.6610,  12.0701, -22.8142,  14.9336, -68.2391,   2.0691,  10.3239, -14.0364,
			-31.6674,  10.1955,  40.7744,   8.2412, -15.9020,  -4.8268,  -1.6626,  18.0331, -68.9970,   8.6007,
			-32.3022,  32.0543,  41.3590,  11.0060,  56.3765,  16.5019, -16.4587,  26.8892,  -5.9711,  -5.3946,
			  2.0255,  -6.1028,   7.0672, -13.5116,  12.4027,  19.6118,  67.8030,  21.9640,  25.6313,  17.1018,
			 59.1410,  25.5038, -35.0476,  -7.7686, -26.7387,  13.0637,  49.7522, -19.3631,  71.3213,  19.9536 );

	ASSERT_SUCCESS( matrixAdd(m1, m2) );
	ASSERT_MATRIX_EQUAL( m1, m1AddM2 );
	ASSERT_MATRIX_EQUAL( m2, m2Copy );
	ASSERT_SUCCESS( matrixAdd(m2, m1Copy) );
	ASSERT_MATRIX_EQUAL( m2, m1AddM2 );

	matrixDestroy( m1 );
	matrixDestroy( m1Copy );
	matrixDestroy( m2 );
	matrixDestroy( m2Copy );
	matrixDestroy( m1AddM2 );
	/* NOT FOR STUDENTS END */
	return true;
}

bool testSubtractBoundary()
{
	Matrix m1 = matrixCreate( 6, 5 );
	Matrix m3 = matrixCreate( 13, 11 );
	Matrix m4 = matrixCreate( 12, 10 );
	Matrix m5 = matrixCreate( 12, 11 );
	Matrix m6 = matrixCreate( 13, 10 );

	ASSERT_NULL( matrixSubtract(NULL, NULL) );
	ASSERT_NULL( matrixSubtract(NULL, m1) );
	ASSERT_NULL( matrixSubtract(m1, NULL) );

	ASSERT_TRUE( matrixSubtract(m1, m3) == MATRIX_BAD_DIMENSIONS );
	ASSERT_TRUE( matrixSubtract(m1, m4) == MATRIX_BAD_DIMENSIONS );
	ASSERT_TRUE( matrixSubtract(m4, m5) == MATRIX_BAD_DIMENSIONS );
	ASSERT_TRUE( matrixSubtract(m4, m6) == MATRIX_BAD_DIMENSIONS );

	matrixDestroy( m1 );
	matrixDestroy( m3 );
	matrixDestroy( m4 );
	matrixDestroy( m5 );
	matrixDestroy( m6 );

	return true;
}

bool testSubtractFunctionality()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	Matrix m1 = initMatrix( 6, 5,
			-36.8584,   6.1936, -37.6856,   4.2478, -15.1382,   1.5156, -10.2597,   7.4388,  -1.3487,   9.7963,
			-29.8706,   3.4318, -42.8484,   9.6614, -27.2463,  13.8947, -41.8660,  -2.4969,  37.0781,   6.9331,
			-37.6850,  -4.5447,   5.3857,  -2.9498,   0.9543,   1.4299,   0.1206,  -0.2220, -34.0706,  13.1711,
			 -0.9622,  12.6448,  25.6145,   7.2448,  38.1982,  -4.9177,  -6.4182,   5.6476, -10.3395, -13.5742,
			-28.8349, -10.8816, -17.6776,   9.7214,  12.1189,   3.4647,  46.7707,  13.7093,  40.1715,  -4.1508,
			 37.2138,   6.6870, -30.1756,  -5.1486, -37.4558,  -4.0415,  29.2906,  -4.9951,  39.2444,   4.7170 );
	Matrix m1Copy = initMatrix( 6, 5,
			-36.8584,   6.1936, -37.6856,   4.2478, -15.1382,   1.5156, -10.2597,   7.4388,  -1.3487,   9.7963,
			-29.8706,   3.4318, -42.8484,   9.6614, -27.2463,  13.8947, -41.8660,  -2.4969,  37.0781,   6.9331,
			-37.6850,  -4.5447,   5.3857,  -2.9498,   0.9543,   1.4299,   0.1206,  -0.2220, -34.0706,  13.1711,
			 -0.9622,  12.6448,  25.6145,   7.2448,  38.1982,  -4.9177,  -6.4182,   5.6476, -10.3395, -13.5742,
			-28.8349, -10.8816, -17.6776,   9.7214,  12.1189,   3.4647,  46.7707,  13.7093,  40.1715,  -4.1508,
			 37.2138,   6.6870, -30.1756,  -5.1486, -37.4558,  -4.0415,  29.2906,  -4.9951,  39.2444,   4.7170 );
	Matrix m2 = initMatrix( 6, 5,
			 16.1880,  23.5643, -15.6259,  21.7428,  -2.1444,   7.1688, -14.0346,  -6.2458,  12.3014,   7.5387,
			 27.5793, -10.4556,   3.1874,   2.4087,   4.4321,   1.0389, -26.3731,   4.5660, -26.7542, -20.9695,
			  6.0176,  14.7402,  35.3887,  11.1910, -16.8563,  -6.2567,  -1.7832,  18.2551, -34.9264,  -4.5704,
			-31.3400,  19.4095,  15.7445,   3.7612,  18.1783,  21.4196, -10.0405,  21.2416,   4.3684,   8.1796,
			 30.8604,   4.7788,  24.7448, -23.2330,   0.2838,  16.1471,  21.0323,   8.2547, -14.5402,  21.2526,
			 21.9272,  18.8168,  -4.8720,  -2.6200,  10.7171,  17.1052,  20.4616, -14.3680,  32.0769,  15.2366 );
	Matrix m2Copy = initMatrix( 6, 5,
			 16.1880,  23.5643, -15.6259,  21.7428,  -2.1444,   7.1688, -14.0346,  -6.2458,  12.3014,   7.5387,
			 27.5793, -10.4556,   3.1874,   2.4087,   4.4321,   1.0389, -26.3731,   4.5660, -26.7542, -20.9695,
			  6.0176,  14.7402,  35.3887,  11.1910, -16.8563,  -6.2567,  -1.7832,  18.2551, -34.9264,  -4.5704,
			-31.3400,  19.4095,  15.7445,   3.7612,  18.1783,  21.4196, -10.0405,  21.2416,   4.3684,   8.1796,
			 30.8604,   4.7788,  24.7448, -23.2330,   0.2838,  16.1471,  21.0323,   8.2547, -14.5402,  21.2526,
			 21.9272,  18.8168,  -4.8720,  -2.6200,  10.7171,  17.1052,  20.4616, -14.3680,  32.0769,  15.2366 );
	Matrix m1SubtractM2 = initMatrix(6, 5,
			-53.0464, -17.3707, -22.0597, -17.4950, -12.9938,  -5.6532,   3.7749,  13.6846, -13.6501,   2.2576,
			-57.4499,  13.8874, -46.0358,   7.2527, -31.6784,  12.8558, -15.4929,  -7.0629,  63.8323,  27.9026,
			-43.7026, -19.2849, -30.0030, -14.1408,  17.8106,   7.6866,   1.9038, -18.4771,   0.8558,  17.7415,
			 30.3778,  -6.7647,   9.8700,   3.4836,  20.0199, -26.3373,   3.6223, -15.5940, -14.7079, -21.7538,
			-59.6953, -15.6604, -42.4224,  32.9544,  11.8351, -12.6824,  25.7384,   5.4546,  54.7117, -25.4034,
			 15.2866, -12.1298, -25.3036,  -2.5286, -48.1729, -21.1467,   8.8290,   9.3729,   7.1675, -10.5196 );
	Matrix m2SubtractM1 = initMatrix(6, 5,
			 53.0464,  17.3707,  22.0597,  17.4950,  12.9938,   5.6532,  -3.7749, -13.6846,  13.6501,  -2.2576,
			 57.4499, -13.8874,  46.0358,  -7.2527,  31.6784, -12.8558,  15.4929,   7.0629, -63.8323, -27.9026,
			 43.7026,  19.2849,  30.0030,  14.1408, -17.8106,  -7.6866,  -1.9038,  18.4771,  -0.8558, -17.7415,
			-30.3778,   6.7647,  -9.8700,  -3.4836, -20.0199,  26.3373,  -3.6223,  15.5940,  14.7079,  21.7538,
			 59.6953,  15.6604,  42.4224, -32.9544, -11.8351,  12.6824, -25.7384,  -5.4546, -54.7117,  25.4034,
			-15.2866,  12.1298,  25.3036,   2.5286,  48.1729,  21.1467,  -8.8290,  -9.3729,  -7.1675,  10.5196 );

	ASSERT_SUCCESS( matrixSubtract(m1, m2) );
	ASSERT_MATRIX_EQUAL( m1, m1SubtractM2 );
	ASSERT_MATRIX_EQUAL( m2, m2Copy );
	ASSERT_SUCCESS( matrixSubtract(m2, m1Copy) );
	ASSERT_MATRIX_EQUAL( m2, m2SubtractM1 );

	matrixDestroy( m1 );
	matrixDestroy( m1Copy );
	matrixDestroy( m2 );
	matrixDestroy( m2Copy );
	matrixDestroy( m1SubtractM2 );
	matrixDestroy( m2SubtractM1 );
	/* NOT FOR STUDENTS END */
	return true;
}

bool testNegateBoundary()
{
	ASSERT_NULL( matrixNegate(NULL) );

	return true;
}

bool testNegateFunctionality()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	Matrix m1 = initMatrix( 9, 5,
			 -1.7433, -32.5823,  -1.5970,  28.7943,   0.1539,  -8.5224,  -1.7520, -19.4107,   1.8117, -21.6897,
			 -0.0164,  -0.8265,   0.3665,  18.7099,  -1.3634,  -8.9247,  -1.4863,  10.7106,   1.9820,  22.1191,
			  1.5433,  26.5919,  -1.6822, -29.0708,   1.0474, -17.3696,   2.2748,  23.4546,  -1.5549,  11.7563,
			  0.6643,  37.7751,   2.0303,   0.6857,  -1.7568,  27.9591,  -2.4205,  26.8562,   0.8036, -36.0129,
			  0.9420, -37.6662,  -2.1133, -25.1688,   0.7906,  18.3542,   2.2876,  -7.7431,   2.2062,  21.7190,
			  0.6979,   3.2382,  -0.8073,  25.1645,   0.6699,  -3.9617,  -2.3715, -29.2225,   2.3785,  32.1148,
			  1.1466,  27.4625,   0.4031,  32.5288,  -1.3535,  15.9326,   2.3556, -31.8986,  -1.9603,  -0.5842,
			  1.7992,  31.0946,  -0.1238, -25.1192,  -1.5889,  33.7692,  -1.0120, -10.6045,  -1.6055,  25.3849,
			  0.6348,  26.2466,   1.5266,  29.1640,  -1.6682, -24.7670,   0.1254,  24.9968,   1.2328, -28.0171);
	Matrix m1Copy = initMatrix( 9, 5,
			 -1.7433, -32.5823,  -1.5970,  28.7943,   0.1539,  -8.5224,  -1.7520, -19.4107,   1.8117, -21.6897,
			 -0.0164,  -0.8265,   0.3665,  18.7099,  -1.3634,  -8.9247,  -1.4863,  10.7106,   1.9820,  22.1191,
			  1.5433,  26.5919,  -1.6822, -29.0708,   1.0474, -17.3696,   2.2748,  23.4546,  -1.5549,  11.7563,
			  0.6643,  37.7751,   2.0303,   0.6857,  -1.7568,  27.9591,  -2.4205,  26.8562,   0.8036, -36.0129,
			  0.9420, -37.6662,  -2.1133, -25.1688,   0.7906,  18.3542,   2.2876,  -7.7431,   2.2062,  21.7190,
			  0.6979,   3.2382,  -0.8073,  25.1645,   0.6699,  -3.9617,  -2.3715, -29.2225,   2.3785,  32.1148,
			  1.1466,  27.4625,   0.4031,  32.5288,  -1.3535,  15.9326,   2.3556, -31.8986,  -1.9603,  -0.5842,
			  1.7992,  31.0946,  -0.1238, -25.1192,  -1.5889,  33.7692,  -1.0120, -10.6045,  -1.6055,  25.3849,
			  0.6348,  26.2466,   1.5266,  29.1640,  -1.6682, -24.7670,   0.1254,  24.9968,   1.2328, -28.0171);

	Matrix expected = initMatrix( 9, 5,
			  1.7433,  32.5823,   1.5970, -28.7943,  -0.1539,   8.5224,   1.7520,  19.4107,  -1.8117,  21.6897,
			  0.0164,   0.8265,  -0.3665, -18.7099,   1.3634,   8.9247,   1.4863, -10.7106,  -1.9820, -22.1191,
			 -1.5433, -26.5919,   1.6822,  29.0708,  -1.0474,  17.3696,  -2.2748, -23.4546,   1.5549, -11.7563,
			 -0.6643, -37.7751,  -2.0303,  -0.6857,   1.7568, -27.9591,   2.4205, -26.8562,  -0.8036,  36.0129,
			 -0.9420,  37.6662,   2.1133,  25.1688,  -0.7906, -18.3542,  -2.2876,   7.7431,  -2.2062, -21.7190,
			 -0.6979,  -3.2382,   0.8073, -25.1645,  -0.6699,   3.9617,   2.3715,  29.2225,  -2.3785, -32.1148,
			 -1.1466, -27.4625,  -0.4031, -32.5288,   1.3535, -15.9326,  -2.3556,  31.8986,   1.9603,   0.5842,
			 -1.7992, -31.0946,   0.1238,  25.1192,   1.5889, -33.7692,   1.0120,  10.6045,   1.6055, -25.3849,
			 -0.6348, -26.2466,  -1.5266, -29.1640,   1.6682,  24.7670,  -0.1254, -24.9968,  -1.2328,  28.0171);

	ASSERT_SUCCESS( matrixNegate(m1) );
	ASSERT_MATRIX_EQUAL( m1, expected );
	ASSERT_SUCCESS( matrixNegate(m1) );
	ASSERT_MATRIX_EQUAL( m1, m1Copy );
	matrixDestroy( m1 );
	matrixDestroy( m1Copy );
	matrixDestroy( expected );

	/* NOT FOR STUDENTS END */
	return true;
}

bool testMultiplyFunctionality2()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	Matrix m1 = initMatrix( 3, 4,
			 -2.9027,  -2.8801,   1.0707,   0.4359,  -2.7254,   0.2384,   1.6784,   1.9904,
			 -0.9220,   2.7330,   0.3329,  -2.6294,  -2.7791,   0.6392,  -0.2811,  -3.8418,
			  0.5011,   0.1256,  -1.4801,   2.5613,  -2.9044,  -0.7016,  -3.0938,   0.8538);
	Matrix m2 = initMatrix( 4, 7,
			 -0.4608,   0.1817,  -1.9899,  -1.7010,  -0.5010,   0.6403,  -4.2192,  -0.1661,  -0.4231,  -1.8973,  -1.1490,   0.5034,  -0.3144,  -1.5408,
			  1.3732,   0.9971,   2.6961,   0.6534,  -0.3881,   0.7604,  -2.8146,   1.2244,   2.7975,  -1.7727,  -0.8487,  -1.8819,   4.0794,  -1.0557,
			 -1.7687,  -1.5005,   2.6655,   0.8146,   0.8984,   1.4149,   3.9923,   1.2991,   3.8599,  -1.4283,  -0.5506,  -0.1107,  -1.3077,  -0.8437,
			  0.9670,  -0.1871,   4.0868,   1.6758,   3.0836,  -0.1284,   4.0313,  -1.2383,   1.5545,  -1.3143,   1.6078,   0.7138,  -1.4488,  -1.3090);
	Matrix expected = initMatrix( 3, 7,
			10.07007850, 7.74439512, -0.45605170, 21.90580286, 5.19665378, 2.50941976, 6.26190543, 16.07467131, -5.42248740, 11.74830804, 7.50144188, 4.03176284, 5.24185535, 2.93280325,
			7.89107381, -5.32859157, 6.46000804, -27.47348606, -4.17905523, -15.85435485, -11.18937430, -19.76743026, -13.45475695, -6.51889179, -1.65595813, -8.42105690, 2.63492147, -3.07364992,
			-3.58777109, 9.07798954, -27.69223904, -1.09519819, -12.75169137, -3.57131124, -23.16210818, -8.93556089, -15.47382937, 15.61879375, 1.37512184, 0.59176746, 5.50808871, 17.38024863);

	Matrix result = NULL;

	ASSERT_SUCCESS( matrixMultiply(m1, m2, &result) );
	ASSERT_MATRIX_EQUAL( result, expected );

	matrixDestroy( m1 );
	matrixDestroy( m2 );
	matrixDestroy( expected );
	matrixDestroy( result );

	/* NOT FOR STUDENTS END */
	return true;
}

bool testMultiplyBoundary1()
{
	Matrix m1 = matrixCreate( 5, 5 );
	Matrix m2 = matrixCreate( 5, 5 );
	Matrix m3 = matrixCreate( 7, 5 );
	Matrix result = (Matrix)154;

	ASSERT_NULL( matrixMultiply(NULL, NULL, NULL) );
	ASSERT_NULL( matrixMultiply(m1, NULL, NULL) );
	ASSERT_NULL( matrixMultiply(NULL, m1, NULL) );
	ASSERT_NULL( matrixMultiply(NULL, NULL, &result) );
	ASSERT_NULL( matrixMultiply(m1, m2, NULL) );
	ASSERT_NULL( matrixMultiply(m1, m3, NULL) );

	ASSERT_TRUE( matrixMultiply( m1, m3, &result ) == MATRIX_BAD_DIMENSIONS );
	ASSERT_SUCCESS( matrixMultiply( m3, m1, &result) );

	matrixDestroy( m1 );
	matrixDestroy( m2 );
	matrixDestroy( m3 );
	matrixDestroy( result );

	return true;
}

bool testMultiplyBoundary2()
{
	Matrix m1 = matrixCreate( 5, 5 );
	Matrix m2 = matrixCreate( 5, 5 );
	Matrix result = (Matrix)154;

	ASSERT_SUCCESS( matrixMultiply( m1, m2, &result ) );

	matrixDestroy( m1 );
	matrixDestroy( m2 );
	matrixDestroy( result );

	return true;
}


bool testMultiplyFunctionality1()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	Matrix m1 = initMatrix( 5, 5,
			-0.7255000000000000, -4.9898999999999996, 0.7357000000000000, -3.9708000000000001, 0.9862000000000000, -4.9234000000000000, -0.6002000000000000, 3.4173000000000000, -0.9584000000000000, 0.8646000000000000,
			0.6986000000000000, 4.0660999999999996, -0.4886000000000000, 4.9687999999999999, 0.5578000000000000, 0.4528000000000000, -0.2664000000000000, -4.5175000000000001, 0.0670000000000000, 2.7804000000000002,
			-1.1496999999999999, 1.8004000000000000, 0.2530000000000000, -1.4103000000000001, -0.6980000000000000, 0.0911000000000000, -0.7905000000000000, -1.8368000000000000, -0.6115000000000000, 2.2770000000000001,
			0.7381000000000000, 0.1495000000000000, -0.0931000000000000, 1.2524000000000000, 1.4085000000000001, -2.5322000000000000, -0.9148000000000000, 2.8342000000000001, -0.1117000000000000, 1.5099000000000000,
			0.9294000000000000, 0.2207000000000000, -1.2382000000000000, -1.0663000000000000, -0.9487000000000000, -4.5460000000000003, 0.6161000000000000, 4.7240000000000002, 1.2757000000000001, 1.6462000000000001);
	Matrix m1Copy = initMatrix( 5, 5,
			-0.7255000000000000, -4.9898999999999996, 0.7357000000000000, -3.9708000000000001, 0.9862000000000000, -4.9234000000000000, -0.6002000000000000, 3.4173000000000000, -0.9584000000000000, 0.8646000000000000,
			0.6986000000000000, 4.0660999999999996, -0.4886000000000000, 4.9687999999999999, 0.5578000000000000, 0.4528000000000000, -0.2664000000000000, -4.5175000000000001, 0.0670000000000000, 2.7804000000000002,
			-1.1496999999999999, 1.8004000000000000, 0.2530000000000000, -1.4103000000000001, -0.6980000000000000, 0.0911000000000000, -0.7905000000000000, -1.8368000000000000, -0.6115000000000000, 2.2770000000000001,
			0.7381000000000000, 0.1495000000000000, -0.0931000000000000, 1.2524000000000000, 1.4085000000000001, -2.5322000000000000, -0.9148000000000000, 2.8342000000000001, -0.1117000000000000, 1.5099000000000000,
			0.9294000000000000, 0.2207000000000000, -1.2382000000000000, -1.0663000000000000, -0.9487000000000000, -4.5460000000000003, 0.6161000000000000, 4.7240000000000002, 1.2757000000000001, 1.6462000000000001);
	Matrix m2 = initMatrix( 5, 5,
			0.0351000000000000, -0.5999000000000000, -0.0608000000000000, -1.0255000000000001, 0.0224000000000000, -0.9787000000000000, 0.1380000000000000, 0.9551000000000000, 0.4535000000000000, -1.1807000000000001,
			-0.1016000000000000, 0.9406000000000000, 0.0476000000000000, -1.3136000000000001, -0.0096000000000000, 0.4542000000000000, 0.2094000000000000, 1.3145000000000000, -0.3372000000000000, -1.1796000000000000,
			0.1705000000000000, -1.2699000000000000, -0.1049000000000000, 0.6055000000000000, -0.4113000000000000, -0.0039000000000000, 0.4926000000000000, -1.4990000000000001, 0.4705000000000000, -0.3987000000000000,
			-0.0595000000000000, -0.4366000000000000, -0.1017000000000000, -1.2405999999999999, -0.2491000000000000, -0.6465000000000000, 0.4322000000000000, 0.4212000000000000, 0.0970000000000000, -0.7812000000000000,
			-0.3671000000000000, -1.1040000000000001, 0.2513000000000000, 0.3504000000000000, -0.0524000000000000, 0.9917000000000000, -0.4078000000000000, -1.4779000000000000, -0.2598000000000000, -0.4616000000000000);
	Matrix m2Copy = initMatrix( 5, 5,
			0.0351000000000000, -0.5999000000000000, -0.0608000000000000, -1.0255000000000001, 0.0224000000000000, -0.9787000000000000, 0.1380000000000000, 0.9551000000000000, 0.4535000000000000, -1.1807000000000001,
			-0.1016000000000000, 0.9406000000000000, 0.0476000000000000, -1.3136000000000001, -0.0096000000000000, 0.4542000000000000, 0.2094000000000000, 1.3145000000000000, -0.3372000000000000, -1.1796000000000000,
			0.1705000000000000, -1.2699000000000000, -0.1049000000000000, 0.6055000000000000, -0.4113000000000000, -0.0039000000000000, 0.4926000000000000, -1.4990000000000001, 0.4705000000000000, -0.3987000000000000,
			-0.0595000000000000, -0.4366000000000000, -0.1017000000000000, -1.2405999999999999, -0.2491000000000000, -0.6465000000000000, 0.4322000000000000, 0.4212000000000000, 0.0970000000000000, -0.7812000000000000,
			-0.3671000000000000, -1.1040000000000001, 0.2513000000000000, 0.3504000000000000, -0.0524000000000000, 0.9917000000000000, -0.4078000000000000, -1.4779000000000000, -0.2598000000000000, -0.4616000000000000);
	Matrix expected = initMatrix( 5, 5,
			-2.6087451400000008, 0.0630964900000004, -3.6196483300000022, 1.2840886600000001, -1.9766264000000004, 1.5327255000000000, 3.1148868499999995, -2.8615314600000001, -9.3921083400000036, -2.6267286999999988,
			-0.4016454499999998, -2.5814764399999999, 3.7636526900000029, 1.7170727499999998, -4.0996919000000007, 0.1676139500000000, -3.5979427899999989, -2.2840738400000005, 9.2977022699999985, -1.0727008700000000,
			4.3205852800000004, 2.3297112999999996, -3.0561271500000000, 1.7633239199999999, -0.5547656000000002, 1.5021103799999997, 3.8678750700000002, -0.8728420400000000, -0.7383013399999999, 2.8022745000000002,
			-1.0286706600000002, -3.0729474000000003, 6.1866568099999997, 1.7213347100000000, -0.4256166300000003, -0.0418106899999999, -4.1207544199999990, -2.1042686100000005, 4.5244094100000005, -2.2202861299999999,
			-1.2660002000000006, -3.7392142800000001, 7.1040039200000002, 0.1275938100000001, 2.3067010100000003, 0.0204494300000004, -6.0327265800000003, -2.0054921500000003, 1.7615329599999998, -1.9773795600000001);

	Matrix result = NULL;

	ASSERT_SUCCESS( matrixMultiply(m1, m2, &result) );

	ASSERT_MATRIX_EQUAL( m1, m1Copy );
	ASSERT_MATRIX_EQUAL( m2, m2Copy );
	ASSERT_MATRIX_EQUAL( result, expected );

	matrixDestroy( result );
	Matrix I = matrixCreateUnit(5);
	ASSERT_SUCCESS( matrixMultiply(m1, I, &result) );
	ASSERT_MATRIX_EQUAL( result, m1 );

	matrixDestroy( result );
	ASSERT_SUCCESS( matrixMultiply(I, m1, &result) );
	ASSERT_MATRIX_EQUAL( result, m1 );


	matrixDestroy( m1 );
	matrixDestroy( m2 );
	matrixDestroy( m1Copy );
	matrixDestroy( m2Copy );
	matrixDestroy( expected );
	matrixDestroy( result );
	matrixDestroy( I );

	/* NOT FOR STUDENTS END */
	return true;
}

bool testSwapRowsBoundary()
{
	Matrix m = matrixCreate( 5, 6 );
	Matrix mCopy = matrixCreate( 5, 6 );

	matrixSet( m, 0, 2, complexCreate( 34, 23 ) );
	matrixSet( mCopy, 0, 2, complexCreate( 34, 23 ) );

	ASSERT_NULL( matrixSwapRows( NULL, 3, 5 ) );
	ASSERT_TRUE( matrixSwapRows( m, 0, -20 ) == MATRIX_OUT_OF_BOUNDS );
	ASSERT_TRUE( matrixSwapRows( m, -1, 5 ) == MATRIX_OUT_OF_BOUNDS );
	ASSERT_TRUE( matrixSwapRows( m, 0, 6 ) == MATRIX_OUT_OF_BOUNDS );

	ASSERT_SUCCESS( matrixSwapRows( m, 0, 0 ) );
	ASSERT_MATRIX_EQUAL( m, mCopy );

	matrixDestroy( m );
	matrixDestroy( mCopy );

	return true;
}

bool testSwapRowsFunctionality()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	Matrix m = initMatrix( 5, 6,
			  2.5727,   0.2172,  -4.9339,  -0.5274,   1.3601,  -0.3103,  -3.3571,  -1.1794,   2.8811,  -0.5917,   4.3060,  -0.6372,
			  0.4669,  -1.0336,   0.9730,   0.6481,   0.2556,   0.2302,  -2.1960,   0.6964,   3.6961,  -0.1229,  -4.5485,   0.9501,
			 -1.4261,   0.0071,   1.5918,   0.1588,  -2.4038,  -1.4418,  -2.4057,   1.4116,   2.8754,  -1.3559,  -2.5935,  -0.1484,
			  2.0100,   0.2032,   0.8001,  -1.0732,  -4.4883,   0.2327,   0.4710,   0.3267,   4.6943,  -0.3439,  -4.9114,   0.9199,
			 -3.9078,  -0.9352,   4.0995,  -0.3589,   2.3195,   1.2966,   0.4127,   0.6590,  -3.1953,  -0.4149,   1.7159,   0.8705);
	Matrix mCopy = initMatrix( 5, 6,
			  2.5727,   0.2172,  -4.9339,  -0.5274,   1.3601,  -0.3103,  -3.3571,  -1.1794,   2.8811,  -0.5917,   4.3060,  -0.6372,
			  0.4669,  -1.0336,   0.9730,   0.6481,   0.2556,   0.2302,  -2.1960,   0.6964,   3.6961,  -0.1229,  -4.5485,   0.9501,
			 -1.4261,   0.0071,   1.5918,   0.1588,  -2.4038,  -1.4418,  -2.4057,   1.4116,   2.8754,  -1.3559,  -2.5935,  -0.1484,
			  2.0100,   0.2032,   0.8001,  -1.0732,  -4.4883,   0.2327,   0.4710,   0.3267,   4.6943,  -0.3439,  -4.9114,   0.9199,
			 -3.9078,  -0.9352,   4.0995,  -0.3589,   2.3195,   1.2966,   0.4127,   0.6590,  -3.1953,  -0.4149,   1.7159,   0.8705);

	Matrix expected = initMatrix( 5, 6,
			  2.5727,   0.2172,  -4.9339,  -0.5274,   1.3601,  -0.3103,  -3.3571,  -1.1794,   2.8811,  -0.5917,   4.3060,  -0.6372,
			  0.4669,  -1.0336,   0.9730,   0.6481,   0.2556,   0.2302,  -2.1960,   0.6964,   3.6961,  -0.1229,  -4.5485,   0.9501,
			 -3.9078,  -0.9352,   4.0995,  -0.3589,   2.3195,   1.2966,   0.4127,   0.6590,  -3.1953,  -0.4149,   1.7159,   0.8705,
			  2.0100,   0.2032,   0.8001,  -1.0732,  -4.4883,   0.2327,   0.4710,   0.3267,   4.6943,  -0.3439,  -4.9114,   0.9199,
			 -1.4261,   0.0071,   1.5918,   0.1588,  -2.4038,  -1.4418,  -2.4057,   1.4116,   2.8754,  -1.3559,  -2.5935,  -0.1484);

	ASSERT_SUCCESS( matrixSwapRows(m, 1, 1) );
	ASSERT_MATRIX_EQUAL( m, mCopy );
	ASSERT_SUCCESS( matrixSwapRows(m, 2, 4) );
	ASSERT_MATRIX_EQUAL( m, expected );
	ASSERT_SUCCESS( matrixSwapRows(m, 2, 4) );
	ASSERT_MATRIX_EQUAL( m, mCopy );

	matrixDestroy( m );
	matrixDestroy( mCopy );
	matrixDestroy( expected );

	/* NOT FOR STUDENTS END */
	return true;
}

bool testMultiplyRowByScalarBoundary()
{
	Matrix m = matrixCreate( 4, 6 );
	Matrix zeroMatrix = matrixCreate( 4, 6 );
	Complex scalar = complexCreate(3.4, -7.6);

	matrixSet( m, 0, 0, scalar );

	ASSERT_NULL( matrixMultiplyRowByScalar(NULL, 3, scalar) );
	ASSERT_TRUE( matrixMultiplyRowByScalar( m, -20, scalar ) == MATRIX_OUT_OF_BOUNDS );
	ASSERT_TRUE( matrixMultiplyRowByScalar( m, 4, scalar ) == MATRIX_OUT_OF_BOUNDS );

	ASSERT_SUCCESS( matrixMultiplyRowByScalar(m, 0, complexCreate(0,0) ) );
	ASSERT_MATRIX_EQUAL( m, zeroMatrix );

	matrixDestroy( m );
	matrixDestroy( zeroMatrix );

	return true;
}

bool testMultiplyRowByScalarFunctionality()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	Matrix m = initMatrix( 4, 6,
			13.04280000, 11.76530000, -9.76650000, 6.32690000, 23.67780000, 15.23310000, 28.95410000, 14.60070000, 9.24790000, -23.70450000, -7.96080000, -0.70490000,
			19.75750000, -10.64820000, 10.47720000, -22.37540000, 23.38780000, 20.04750000, 17.02300000, -9.97620000, -11.08190000, 2.85510000, 16.80450000, -6.33680000,
			-11.60410000, -12.99720000, 22.74750000, 7.02330000, -20.61420000, -9.15300000, 23.62600000, -13.61910000, 8.84190000, -5.29040000, -20.91050000, -24.12250000,
			-11.88800000, 22.88020000, 16.49210000, -16.93850000, 22.06410000, -20.05220000, -27.25300000, -16.49590000, 23.92430000, 13.75640000, 1.24270000, -15.74700000);
	Matrix mCopy = initMatrix( 4, 6,
			13.04280000, 11.76530000, -9.76650000, 6.32690000, 23.67780000, 15.23310000, 28.95410000, 14.60070000, 9.24790000, -23.70450000, -7.96080000, -0.70490000,
			19.75750000, -10.64820000, 10.47720000, -22.37540000, 23.38780000, 20.04750000, 17.02300000, -9.97620000, -11.08190000, 2.85510000, 16.80450000, -6.33680000,
			-11.60410000, -12.99720000, 22.74750000, 7.02330000, -20.61420000, -9.15300000, 23.62600000, -13.61910000, 8.84190000, -5.29040000, -20.91050000, -24.12250000,
			-11.88800000, 22.88020000, 16.49210000, -16.93850000, 22.06410000, -20.05220000, -27.25300000, -16.49590000, 23.92430000, 13.75640000, 1.24270000, -15.74700000);
	Matrix expected = initMatrix( 4, 6,
			13.04280000, 11.76530000, -9.76650000, 6.32690000, 23.67780000, 15.23310000, 28.95410000, 14.60070000, 9.24790000, -23.70450000, -7.96080000, -0.70490000,
			-13.75082000, -186.36088000, -134.43056000, -155.70308000, 231.87952000, -109.58578000, -17.94092000, -163.29388000, -15.97970000, 93.92978000, 8.97562000, -149.25932000,
			-11.60410000, -12.99720000, 22.74750000, 7.02330000, -20.61420000, -9.15300000, 23.62600000, -13.61910000, 8.84190000, -5.29040000, -20.91050000, -24.12250000,
			-11.88800000, 22.88020000, 16.49210000, -16.93850000, 22.06410000, -20.05220000, -27.25300000, -16.49590000, 23.92430000, 13.75640000, 1.24270000, -15.74700000);

	Complex scalar = complexCreate(3.4, -7.6);
	Complex one = complexCreate(1, 0);

	ASSERT_SUCCESS( matrixMultiplyRowByScalar(m, 1, one) );
	ASSERT_MATRIX_EQUAL( m, mCopy );
	ASSERT_SUCCESS( matrixMultiplyRowByScalar(m, 1, scalar) );
	ASSERT_MATRIX_EQUAL( m, expected );

	matrixDestroy( m );
	matrixDestroy( mCopy );
	matrixDestroy( expected );

	/* NOT FOR STUDENTS END */
	return true;
}

bool testSubtractRowBoundary()
{
	Matrix m = matrixCreate( 5, 6 );
	Matrix mCopy = matrixCreate( 5, 6 );
	matrixSet( m, 0, 3, complexCreate( 23, -54 ) );

	Complex scalar = complexCreate(3.4, -7.6);
	ASSERT_NULL( matrixSubtractRow(NULL, 3, 5, scalar) );
	ASSERT_TRUE( matrixSubtractRow( m, 0, -20, scalar ) == MATRIX_OUT_OF_BOUNDS );
	ASSERT_TRUE( matrixSubtractRow( m, -1, 5, scalar ) == MATRIX_OUT_OF_BOUNDS );
	ASSERT_TRUE( matrixSubtractRow( m, 0, 5, scalar ) == MATRIX_OUT_OF_BOUNDS );

	ASSERT_SUCCESS( matrixSubtractRow( m, 0, 0, complexCreate(1,0) ) );
	ASSERT_MATRIX_EQUAL( m, mCopy );

	matrixDestroy( m );
	matrixDestroy( mCopy );

	return true;
}

bool testSubtractRowFunctionality()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	Matrix m = initMatrix( 5, 6,
			3.24700000, -2.31570000, 25.53980000, 8.90220000, 18.13220000, 20.29330000, -28.68540000, 12.98050000, -17.63300000, 8.77890000, -32.63370000, 3.70430000,
			-25.66430000, -23.23120000, 27.21500000, -16.49860000, -39.74080000, 3.13760000, -23.05010000, 3.97670000, -8.31490000, 13.92650000, 10.19490000, -23.31360000,
			-5.73840000, 22.27070000, 35.12980000, 25.29920000, -30.80270000, -26.32310000, -19.53490000, -27.00580000, -17.20530000, 16.76060000, -12.56980000, -13.66080000,
			-31.12760000, -12.00670000, 3.51270000, 9.08080000, -23.19980000, -0.95260000, 39.28980000, 12.00540000, 22.38610000, -25.89640000, -11.92440000, -20.16000000,
			-10.82420000, 6.26330000, 27.65410000, 2.27150000, -22.03700000, 16.93920000, -13.33960000, -2.78150000, -12.20230000, 15.38990000, -37.54150000, 3.54610000);

	Matrix mCopy = initMatrix( 5, 6,
			3.24700000, -2.31570000, 25.53980000, 8.90220000, 18.13220000, 20.29330000, -28.68540000, 12.98050000, -17.63300000, 8.77890000, -32.63370000, 3.70430000,
			-25.66430000, -23.23120000, 27.21500000, -16.49860000, -39.74080000, 3.13760000, -23.05010000, 3.97670000, -8.31490000, 13.92650000, 10.19490000, -23.31360000,
			-5.73840000, 22.27070000, 35.12980000, 25.29920000, -30.80270000, -26.32310000, -19.53490000, -27.00580000, -17.20530000, 16.76060000, -12.56980000, -13.66080000,
			-31.12760000, -12.00670000, 3.51270000, 9.08080000, -23.19980000, -0.95260000, 39.28980000, 12.00540000, 22.38610000, -25.89640000, -11.92440000, -20.16000000,
			-10.82420000, 6.26330000, 27.65410000, 2.27150000, -22.03700000, 16.93920000, -13.33960000, -2.78150000, -12.20230000, 15.38990000, -37.54150000, 3.54610000);

	Matrix expected = initMatrix( 5, 6,
			3.24700000, -2.31570000, 25.53980000, 8.90220000, 18.13220000, 20.29330000, -28.68540000, 12.98050000, -17.63300000, 8.77890000, -32.63370000, 3.70430000,
			-25.66430000, -23.23120000, 27.21500000, -16.49860000, -39.74080000, 3.13760000, -23.05010000, 3.97670000, -8.31490000, 13.92650000, 10.19490000, -23.31360000,
			-16.53720000, -81.28844000, -76.15754000, 227.74726000, -84.61482000, -251.39758000, 46.95914000, -118.92966000, -92.68072000, -128.30254000, 88.12094000, -311.03294000,
			-31.12760000, -12.00670000, 3.51270000, 9.08080000, -23.19980000, -0.95260000, 39.28980000, 12.00540000, 22.38610000, -25.89640000, -11.92440000, -20.16000000,
			-10.82420000, 6.26330000, 27.65410000, 2.27150000, -22.03700000, 16.93920000, -13.33960000, -2.78150000, -12.20230000, 15.38990000, -37.54150000, 3.54610000);

	Complex scalar = complexCreate(3.4, -7.6);
	Complex zero = complexCreate(0, 0);

	ASSERT_SUCCESS( matrixSubtractRow(m, 1, 1, zero) );
	ASSERT_MATRIX_EQUAL( m, mCopy );
	ASSERT_SUCCESS( matrixSubtractRow(m, 2, 4, scalar) );
	ASSERT_MATRIX_EQUAL( m, expected );

	matrixDestroy( m );
	matrixDestroy( mCopy );
	matrixDestroy( expected );

	/* NOT FOR STUDENTS END */
	return true;
}

bool testInverseBoundary1()
{
	Matrix result = NULL;

	Matrix m = matrixCreate( 5, 5 );

	ASSERT_NULL( matrixInverse( m, NULL ) );
	ASSERT_NULL( matrixInverse( NULL, NULL ) );
	ASSERT_NULL( matrixInverse( NULL, &result ) );

	matrixDestroy( m );

	return true;
}

bool testInverseBoundary2()
{
	Matrix result = (Matrix)144;

	Matrix m = matrixCreateUnit( 5 );

	ASSERT_SUCCESS( matrixInverse( m, &result ) );

	matrixDestroy( m );
	matrixDestroy( result );

	return true;
}

bool testInverseFunctionality1()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	Matrix m = initMatrix( 5, 5,
			-4.7000000000, -7.3000000000, -34.9900000000, -29.7000000000, 21.3100000000, -4.6800000000, 26.4700000000, 15.3200000000, 30.4500000000, -17.7000000000,
			27.0000000000, -7.1300000000, -26.0900000000, 12.7000000000, -24.7200000000, 10.6700000000, 13.9900000000, 7.6400000000, -1.7500000000, 20.7800000000,
			-36.8300000000, 6.8200000000, -1.5300000000, 1.3700000000, 17.3500000000, -18.8700000000, 34.3600000000, 26.8400000000, 29.2300000000, 13.5600000000,
			37.2000000000, -31.9000000000, 29.1600000000, -28.4000000000, -19.0000000000, -28.0700000000, 36.3800000000, -16.5600000000, -35.7100000000, 25.3600000000,
			-16.8600000000, -7.5300000000, -16.2400000000, -6.2800000000, -31.3600000000, -2.1700000000, 2.6000000000, -18.7500000000, -27.8500000000, 14.1400000000);
	Matrix expected = initMatrix( 5, 5,
			0.0007546000, -0.0041874877, 0.0083771106, 0.0059632054, -0.0074466322, -0.0003838484, 0.0069171778, -0.0020008850, -0.0193663520, -0.0041791697,
			-0.0101370043, 0.0124335990, -0.0036375171, -0.0086051010, 0.0026593000, -0.0057298977, -0.0011099925, 0.0029931906, 0.0028102038, 0.0097226076,
			0.0160524090, -0.0168353011, -0.0204655921, 0.0027571463, -0.0033658118, 0.0111842764, 0.0158377992, 0.0041599311, -0.0114242327, -0.0306653422,
			0.0133061708, 0.0049119045, 0.0002057105, -0.0138011740, 0.0036864627, -0.0059738562, 0.0056435574, 0.0123337957, 0.0198812537, -0.0071221076,
			-0.0087849977, 0.0021127231, 0.0097146395, 0.0019584297, 0.0062152071, -0.0072282696, -0.0052811746, -0.0134017305, -0.0229101970, 0.0112014631);
	Matrix result = NULL;

	ASSERT_SUCCESS( matrixInverse( m, &result ) );
	ASSERT_MATRIX_EQUAL( result, expected );

	Matrix I = matrixCreateUnit( 5 );
	Matrix result2 = NULL;
	ASSERT_SUCCESS( matrixMultiply( m, result, &result2 ) );
	ASSERT_MATRIX_EQUAL( result2, I );

	matrixDestroy( m );
	matrixDestroy( expected );
	matrixDestroy( result );
	matrixDestroy( result2 );
	matrixDestroy( I );

	/* NOT FOR STUDENTS END */
	return true;
}

bool testInverseFunctionality2()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	Matrix A = matrixCreate(3,3);
	Matrix Ainv = NULL;

	ASSERT_TRUE( matrixInverse(A,&Ainv) == MATRIX_SINGULAR );
	matrixDestroy(A);

	A = initMatrix( 2, 2,
			1.0, 0.0, 1.0, 0.0,
			1.0, 0.0, 1.0, 0.0 );
	ASSERT_TRUE( matrixInverse(A,&Ainv) == MATRIX_SINGULAR );
	matrixDestroy(A);

	/* NOT FOR STUDENTS END */
	return true;
}

bool testSolveEquationSystemBoundary1()
{
	Matrix result = NULL;

	Matrix a = matrixCreate( 5, 5 );
	Matrix b = matrixCreate( 5, 1 );

	ASSERT_NULL( matrixSolveEquationSystem(NULL, NULL, NULL) );
	ASSERT_NULL( matrixSolveEquationSystem(a, NULL, NULL) );
	ASSERT_NULL( matrixSolveEquationSystem(NULL, b, NULL) );
	ASSERT_NULL( matrixSolveEquationSystem(NULL, NULL, &result) );
	ASSERT_NULL( matrixSolveEquationSystem(a, b, NULL) );

	matrixDestroy( a );
	matrixDestroy( b );

	return true;
}

bool testSolveEquationSystemBoundary2()
{
	Matrix result = (Matrix)144;

	Matrix a = matrixCreateUnit( 5 );
	Matrix b = matrixCreate( 5, 1 );

	ASSERT_SUCCESS( matrixSolveEquationSystem( a, b, &result ) );

	matrixDestroy( a );
	matrixDestroy( b );
	matrixDestroy( result );

	return true;
}

bool testSolveEquationSystemFunctionality1()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	Matrix a = initMatrix( 5, 5,
			-25.6900000000, 2.2100000000, -25.6700000000, 44.0800000000, -23.0900000000, -33.4300000000, 2.8800000000, -5.9400000000, -26.6600000000, -33.1700000000,
			2.7000000000, 0.2000000000, -8.5700000000, -38.6500000000, 21.6200000000, 12.3400000000, 15.7700000000, -8.8400000000, 22.6700000000, -21.9800000000,
			-12.0900000000, -39.0900000000, -4.2400000000, -39.6000000000, 25.3400000000, 22.1800000000, 16.1100000000, 9.7300000000, -26.0300000000, -10.9500000000,
			10.6000000000, -24.3000000000, -22.6800000000, 14.5400000000, -5.8700000000, 27.4700000000, 19.6200000000, 24.3100000000, -25.4100000000, 44.4400000000,
			20.5900000000, -34.4700000000, -22.7100000000, -14.0300000000, -10.0700000000, -20.7900000000, 16.0900000000, 39.7000000000, 11.4200000000, -14.3100000000);
	Matrix b = initMatrix( 5, 1,
			19.7400000000, -13.0400000000,
			-20.9500000000, 21.8600000000,
			17.0800000000, -11.8800000000,
			1.0000000000, 4.8100000000,
			13.8700000000, 33.0400000000);
	Matrix expected_x = initMatrix( 5, 1,
			0.0992057322, 1.5759502405,
			0.0689788301, 0.0553120602,
			-0.6563692240, 0.4029834454,
			-0.5200397614, 1.1381957750,
			-0.0633516402, -0.1688012544);
	Matrix result = NULL;
	Matrix result2 = NULL;

	ASSERT_SUCCESS( matrixSolveEquationSystem( a, b, &result ) );
	ASSERT_MATRIX_EQUAL( result, expected_x );

	ASSERT_SUCCESS( matrixMultiply(a, result, &result2 ) );
	ASSERT_MATRIX_EQUAL( result2, b );

	matrixDestroy( a );
	matrixDestroy( b );
	matrixDestroy( expected_x );
	matrixDestroy( result );
	matrixDestroy( result2 );
	/* NOT FOR STUDENTS END */
	return true;
}

bool testSolveEquationSystemFunctionality2()
{
	// TODO: Add testing code
	/* NOT FOR STUDENTS BEGIN */
	Matrix A = matrixCreate(3,3);
	Matrix b = matrixCreate(3,1);
	Matrix x = NULL;

	ASSERT_TRUE( matrixSolveEquationSystem(A,b,&x) == MATRIX_SINGULAR );

	matrixDestroy(A);
	matrixDestroy(b);
	/* NOT FOR STUDENTS END */
	return true;
}

int testMatrix( int testNumber )
{
	switch( testNumber )
	{
		case 1:		RUN_TEST( testGetSetBoundary() );	break;
		case 2:		RUN_TEST( testGetSetFunctionality() );	break;
		case 3:		RUN_TEST( testIsEqualBoundary() );	break;
		case 4:		RUN_TEST( testIsEqualFunctionality() );	break;
		case 5:		RUN_TEST( testCreateBoundary() );	break;
		case 6:		RUN_TEST( testCreateFunctionality() );	break;
		case 7:		RUN_TEST( testDestroy() );	break;
		case 8:		RUN_TEST( testCreateUnit() );	break;
		case 9:		RUN_TEST( testAddBoundary() );	break;
		case 10:	RUN_TEST( testAddFunctionality() );	break;
		case 11:	RUN_TEST( testSubtractBoundary() );	break;
		case 12:	RUN_TEST( testSubtractFunctionality() );	break;
		case 13:	RUN_TEST( testNegateBoundary() );	break;
		case 14:	RUN_TEST( testNegateFunctionality() );	break;
		case 15:	RUN_TEST( testMultiplyBoundary1() );	break;
		case 16:	RUN_TEST( testMultiplyBoundary2() );	break;
		case 17:	RUN_TEST( testMultiplyFunctionality1() );	break;
		case 18:	RUN_TEST( testMultiplyFunctionality2() );	break;
		case 19:	RUN_TEST( testSwapRowsBoundary() );	break;
		case 20:	RUN_TEST( testSwapRowsFunctionality() );	break;
		case 21:	RUN_TEST( testMultiplyRowByScalarBoundary() );	break;
		case 22:	RUN_TEST( testMultiplyRowByScalarFunctionality() );	break;
		case 23:	RUN_TEST( testSubtractRowBoundary() );	break;
		case 24:	RUN_TEST( testSubtractRowFunctionality() );	break;
		case 25:	RUN_TEST( testInverseBoundary1() );	break;
		case 26:	RUN_TEST( testInverseBoundary2() );	break;
		case 27:	RUN_TEST( testInverseFunctionality1() );	break;
		case 28:	RUN_TEST( testInverseFunctionality2() );	break;
		case 29:	RUN_TEST( testSolveEquationSystemBoundary1() );	break;
		case 30:	RUN_TEST( testSolveEquationSystemBoundary2() );	break;
		case 31:	RUN_TEST( testSolveEquationSystemFunctionality1() );	break;
		case 32:	RUN_TEST( testSolveEquationSystemFunctionality2() );	break;
		default: 	printf( "No test number\n" );
	}

	return 0;
}
